/*
 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
 */


#include <stdio.h>

#include "ulog/ulog.h"
#include "aos/kernel.h"
#include "canopen/canopen.h"
#include "board.h"
#include "co_master_config.h"
#include "canopen/canopen_od.h"
#include "canopen/co_io.h"

static co_io_table_list_t can_io_table[] = {
    {can_io_board_node1, io_board_lost_connection, INVALID_GPIO_COUNT, INVALID_GPIO_COUNT, {0U},{0U},{0U},{0U}, NULL},
    {can_io_board_node2, io_board_lost_connection, INVALID_GPIO_COUNT, INVALID_GPIO_COUNT, {0U},{0U},{0U},{0U}, NULL},
    //{can_io_board_node3, io_board_lost_connection, INVALID_GPIO_COUNT, INVALID_GPIO_COUNT, {0U},{0U},{0U},{0U}, NULL},
    //{can_io_board_node4, io_board_lost_connection, INVALID_GPIO_COUNT, INVALID_GPIO_COUNT, {0U},{0U},{0U},{0U}, NULL}
};

/* REMARK: Below table shall be follow up Table strictly, first count '4' is the same with below, 2nd '5' is MAX OD size of each Node */
static sdo_access_t common_od_access[4][5] = {
    {
        {.access = co_sdo_access_upload,.index = CO_SW_VERSION_INDEX,.sub_index = CO_SW_VERSION_SUB_INDEX,
         .len = CO_IO_BOARD_VERSION_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_DEFAULT,
         .len = CO_IO_OUTPUT_DATA_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_COUNT,
        .len = sizeof(can_io_table[0].output_cnt),.data = &can_io_table[0].output_cnt},
        {.access = co_sdo_access_upload,.index = CO_INPUT_INDEX,.sub_index = CO_INPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[0].input_cnt),.data = &can_io_table[0].input_cnt},
        {.access = co_sdo_access_complete}
    },
    {
        {.access = co_sdo_access_upload,.index = CO_SW_VERSION_INDEX,.sub_index = CO_SW_VERSION_SUB_INDEX,
         .len = CO_IO_BOARD_VERSION_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_DEFAULT,
         .len = CO_IO_OUTPUT_DATA_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[1].output_cnt),.data = &can_io_table[1].output_cnt},
        {.access = co_sdo_access_upload,.index = CO_INPUT_INDEX,.sub_index = CO_INPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[1].input_cnt),.data = &can_io_table[1].input_cnt},
        {.access = co_sdo_access_complete}
    },
    {
        {.access = co_sdo_access_upload,.index = CO_SW_VERSION_INDEX,.sub_index = CO_SW_VERSION_SUB_INDEX,
         .len = CO_IO_BOARD_VERSION_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_DEFAULT,
         .len = CO_IO_OUTPUT_DATA_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[2].output_cnt),.data = &can_io_table[2].output_cnt},
        {.access = co_sdo_access_upload,.index = CO_INPUT_INDEX,.sub_index = CO_INPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[2].input_cnt),.data = &can_io_table[2].input_cnt},
        {.access = co_sdo_access_complete}
    },
    {
        {.access = co_sdo_access_upload,.index = CO_SW_VERSION_INDEX,.sub_index = CO_SW_VERSION_SUB_INDEX,
         .len = CO_IO_BOARD_VERSION_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_DEFAULT,
         .len = CO_IO_OUTPUT_DATA_SIZE,.data = NULL },
        {.access = co_sdo_access_upload,.index = CO_OUTPUT_INDEX,.sub_index = CO_OUTPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[3].output_cnt),.data = &can_io_table[3].output_cnt},
        {.access = co_sdo_access_upload,.index = CO_INPUT_INDEX,.sub_index = CO_INPUT_SUB_INDEX_COUNT,
         .len = sizeof(can_io_table[3].input_cnt),.data = &can_io_table[3].input_cnt},
        {.access = co_sdo_access_complete}
    },
};

static uint8_t get_table_idx(const uint8_t node)
{
    uint8_t rc = 0xFF;
    uint8_t i = 0;
    const uint8_t table_size = get_io_node_size();
    for (; i < table_size; i++) {
        if (can_io_table[i].node == node) {
            rc = i;
            break;
        }
    }

    return rc;
}

co_io_table_list_t *foreach_io_board_table(uint8_t *node_index)
{
    co_io_table_list_t *rc = NULL;
    if (NULL != node_index) {
        if ((*node_index) < get_io_node_size()) {
            rc = &can_io_table[*node_index];
        }
    }

    return rc;
}

sdo_access_t *foreach_od_table(uint8_t *od_table_index, const uint8_t node)
{
    sdo_access_t *rc = NULL;

    if (NULL != od_table_index) {
        const uint8_t index = get_table_idx(node);
        if (index != 0xFF) {
            const uint8_t table_idx = *od_table_index;
            const uint8_t common_od_size = sizeof(common_od_access[index]) / sizeof(common_od_access[index][0]);

            if (table_idx < common_od_size) {
                co_io_table_list_t *list = get_io_node(node);
                if (NULL != list) {
                    if ((CO_SW_VERSION_INDEX == common_od_access[index][table_idx].index)) {

                        if (NULL == list->version) {
                            list->version = (char *)aos_malloc(CO_IO_BOARD_VERSION_SIZE);
                            LOGI(CO_MASTER_LOG_TAG, "Allocate buffer for Board %d Version @ %d", node, table_idx);
                        }

                        if (NULL != list->version) {
                            common_od_access[index][table_idx].data = (void *)list->version;
                            rc = &common_od_access[index][table_idx];
                        } else {
                            LOGE(CO_MASTER_LOG_TAG, "Allocate for version failed, node %d", node);
                        }

                    } else if (CO_OUTPUT_INDEX == common_od_access[index][table_idx].index && CO_OUTPUT_SUB_INDEX_DEFAULT == common_od_access[index][table_idx].sub_index) {
                        common_od_access[index][table_idx].data = (void *)list->output_def_value;
                        rc = &common_od_access[index][table_idx];
                    } else {
                        rc = &common_od_access[index][table_idx];
                    }
                }

            } else {
                LOGE(CO_MASTER_LOG_TAG, "Table Index OverFlow %d size %d", table_idx, common_od_size);
            }
        }
    }

    return rc;
}

co_io_table_list_t *get_io_node(const uint8_t node)
{
    co_io_table_list_t *rc = NULL;
    uint8_t i = 0;
    const uint8_t table_size = get_io_node_size();

    for (; i < table_size; i++) {
        if (can_io_table[i].node == node) {
            rc = &can_io_table[i];
            break;
        }
    }

    return rc;
}

uint8_t get_io_node_size(void)
{
    return sizeof(can_io_table) / sizeof(can_io_table[0]);
}

uint8_t foreach_can_io_node(uint8_t *start)
{
    uint8_t rc = INVALID_NODE;
    if (NULL != start) {
        if (*start < get_io_node_size()) {
            rc = can_io_table[*start].node;
        }
    }

    return rc;
}
